#include "gateway.h"
#include <signal.h>

GateWay::GateWay()
{
	lis_fd = 0;
	ser_fd = 0;
	cli_fd = 0;
	pross_id = 0;
	epfd = 0;
	con_cnt = 0;
	Queue.clear();
	FdList.clear();
}

//服务器初始化
bool GateWay::InitSer()
{
	int on = 1;//status
	struct sockaddr_in addr;   //address
	const int port = 6666;
	const char *ip = "192.168.0.100";
	
	lis_fd = socket(AF_INET,SOCK_STREAM,0);

	setsockopt(lis_fd,SOL_SOCKET,SO_REUSEADDR,&on,sizeof(on));//设置地址重用
	
	addr.sin_family = AF_INET; //agreement
	addr.sin_port = htons(port); //port
	addr.sin_addr.s_addr = inet_addr(ip); //IP adress

	if(bind(lis_fd,(struct sockaddr *)&addr,sizeof(addr)) == -1){
		perror("bind");
		return false;
	}

	listen(lis_fd,512);  //open 
	
	return true;
}

//客户端初始化
bool GateWay::InitCli()
{
	int on = 1;
	int ret = 0;
	struct sockaddr_in ser_addr;
	const int port = 8888;
	const char *ip = "192.168.0.100";
	
	cli_fd = socket(AF_INET,SOCK_STREAM,0);
	setsockopt(cli_fd,SOL_SOCKET,SO_REUSEADDR,&on,sizeof(on));//设置地址重用
	memset(&ser_addr, 0, sizeof(ser_addr));
	ser_addr.sin_family = AF_INET; //agreement
	ser_addr.sin_port = htons(port); //port
	ser_addr.sin_addr.s_addr = inet_addr(ip); //IP adress
	
	ret = connect(cli_fd, (struct sockaddr*)&ser_addr, sizeof(ser_addr));
	if(ret < 0){
		close(cli_fd);
		return false;
	}
	
	return true;
}

//发送事件
void GateWay::SendMsg()
{
	QueInfo info;
	
	while(Queue.size() > 0){
		info = Queue.front();
		Queue.pop_front();
		if(TO_CLIRNT == info.flag){
			//发送到客户端
			write(info.msg.fd, info.msg.data, info.msg.length);
		}else if(TO_SERVER == info.flag){
			//发送到服务器
			write(cli_fd, &(info.msg), sizeof(Message));
		}
	}
}

//将文件描述符添加到内核
void GateWay::AddEvent(int fd, int flag)
{
	struct epoll_event  ev = {0};  //
	ev.events = flag;         
	ev.data.fd = fd;  
	//在内核中添加epoll事件
	epoll_ctl(epfd,EPOLL_CTL_ADD,fd, &ev);
}

//从内核列表中删除文件描述符
void GateWay::DelEvent(int fd)
{
	struct epoll_event  ev = {0}; 
	ev.data.fd = fd;  
	ev.events = EPOLLIN;
	epoll_ctl(epfd, EPOLL_CTL_DEL, fd, &ev);
}

//添加文件描述符列表
void GateWay::AddList(int fd)
{
	FdList.push_back(fd);
}

//从文件描述符列表中删除一个文件描述符
void GateWay::DelList(int fd)
{
	FdList.remove(fd);	
}

//清空客户端文件描述符列表
void GateWay::ClearList()
{
	int fd = 0;
	list<int>::iterator  it;
	while(FdList.size() > 0){
		fd = FdList.front();
		close(fd);
		FdList.pop_front();
	}
}


//状态机，在几个状态之间跳转
//
//网关： 协议转换
//		客户端（多个）   <========> 应用层网关 <==========>服务器（一个）
//
//
//
//
//
void GateWay::MainLoop()
{
	int ret = 0;
	int rc = 0;
	int i = 0;
	const unsigned int timeout = 50;
	struct epoll_event events[64];
	Message msg;
	QueInfo que;
	
	signal(SIGPIPE, SIG_IGN);
	
	pross_id = 1;
	
	while(1){
		switch (pross_id){
		case 0:		//初始化客户端，连接到后台
			if(InitCli()){
				pross_id = 1;
				printf("InitCli success \n");
			}
		break;
		case 1:		//初始化服务器
			if(InitSer()){
				pross_id = 2;
				printf("InitSer success \n");
			}else{
				printf("InitSer failed \n");
			}
		break;
		case 2:
			//
			epfd = epoll_create(64);
			if(epfd > 0){
				AddEvent(cli_fd, EPOLLIN);
				AddEvent(lis_fd, EPOLLIN);
				printf("epoll_create success \n");
				pross_id = 3;
			}
		break;
		case 3:
			memset(events, 0, sizeof(events));
			memset(&que, 0, sizeof(que));
			rc = epoll_wait(epfd, events, 64, timeout);
			if(rc > 0){
				for(i=0; i<rc; i++){	
					int getfd = events[i].data.fd;
					if(getfd == lis_fd){	//监听到有连接请求
						int confd = accept(lis_fd, NULL, NULL);
						if(confd > 0){
							AddEvent(confd, EPOLLIN);
							AddList(confd);
							con_cnt ++;
							printf("connect success fd = %d \n", confd);
						}
					}else if(getfd == cli_fd){	//收到服务器发来的消息
						memset(&msg, 0, sizeof(msg));
						ret = read(getfd, &msg, sizeof(msg));
						if(ret <= 0){	//服务器断开
							pross_id = 5;
							printf("server is leave \n");
						}else if(sizeof(msg) == ret){
							//消息
							que.flag = TO_CLIRNT;
							que.msg = msg;
							Queue.push_back(que);
						}
					}else {
						//收到客户端发来的消息
						char buf[512] = {0};
						ret = read(getfd, buf, sizeof(buf));
						if(ret <= 0){
							//客户端断开
							con_cnt --;
							close(getfd);
							DelEvent(getfd);
							DelList(getfd);
							printf("cli fd = %d leave \n",getfd);
						}else{
							memset(&msg, 0, sizeof(msg));
							msg.fd = getfd;
							msg.length = strlen(buf);
							memcpy(msg.data, buf, strlen(buf));
							que.flag = TO_SERVER;
							que.msg = msg;
							Queue.push_back(que);
						}
					}
				}
			}
		break;
		case 4:
			
		break;
		case 5:
			DelEvent(cli_fd);
			DelEvent(lis_fd);
			ClearList();
			close(cli_fd);
			close(lis_fd);
			close(epfd);
			pross_id = 0;
		break;
		default:
		break;
		}	
		SendMsg();
	}
}

//延时  ms毫秒
void delay(unsigned int ms)
{
	struct  timeval  tv ;
	tv.tv_sec  = ms/1000;
	tv.tv_usec = (1000*(ms%1000));

	select(0, NULL,NULL, NULL, &tv);
	
}
